package main

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"sync"
	"syscall"
	"time"
)

var wg sync.WaitGroup //定义一个锁

type HttpServer struct {
	timeout       int    //定义tcp超时时间
	maxSize       int64  //定义http最大接受的字节数
	listenPort    string //指定http监听端口
	listenAddress string //指定http监听地址
}

func (httpServer *HttpServer) ParseHeader(conn *net.Conn) (map[string]string, error) {
	limitedReader := io.LimitReader(*conn, httpServer.maxSize)
	reader := bufio.NewReader(limitedReader)
	data := map[string]string{}
	headerLines, err := reader.ReadString('\n') //存放的是请求头的原始信息
	if err != nil {
		if err == io.EOF {
			return data, errors.New("Too large data send by the client!\n")
		}
		return data, errors.New("The client had disconnected the connection.\n")
	}
	//判断是否是正常的HTTP请求
	re := regexp.MustCompile(`^GET\s\S+\sHTTP/`) //可以考虑兼容HTTP2.0和1.1，因为ab命令测试的时候不是HTTP 1.1版本，所以这里兼容一下ab测试命令
	if !re.MatchString(headerLines) {

		return data, errors.New("Receving an illegal HTTP request, closed.\n")
	}
	//在请求协议合法的前提下，继续接收请求头
	for {
		line, e := reader.ReadString('\n')
		if e != nil {
			return data, errors.New("The client had disconnected the connection.\n")
		}
		headerLines += line //累计请求头信息
		if line == "\n" || line == "\r\n" {
			break //表示已经遇到空行，已经接收完所有请求头
		}
		//把请求头信息提取出来，存放到map中
		line = strings.TrimSpace(line)
		parts := strings.Split(line, ":")
		if len(parts) == 2 {
			k := strings.TrimSpace(parts[0]) //删除末尾的空格
			v := strings.TrimSpace(parts[1]) //删除末尾的空格
			data[k] = v
		}
	}
	return data, nil
}
func (httpServer *HttpServer) SetResponseContent(body string) string {
	//组装HTTP的相应内容
	response := "HTTP/1.1 200 OK\r\n"
	response += "Content-Type: text/text; charset=utf-8\r\n"
	response += fmt.Sprintf("Content-Length: %d\r\n", len([]byte(body)))
	response += "Connection: close\r\n"
	response += "\r\n" + body
	return response
}
func (httpServer *HttpServer) ResponseHttp(conn *net.Conn) {
	defer wg.Done()
	defer (*conn).Close() //在函数结束前，必须关闭客户端7层连接

	addr, _, e := net.SplitHostPort((*conn).RemoteAddr().String())
	if e != nil {
		log.Printf("A connecting from client failed,reason: invalid remote host: %v\n", addr)
	}
	log.Printf("Receied a request from %v.\n", addr)
	(*conn).SetDeadline(time.Now().Add(3 * time.Second)) // 3 秒超时
	//用bufio的缓存能力，加快处理速度
	data, e := httpServer.ParseHeader(conn) //有返回请求头信息，但是没有使用的需要，故而不处理。
	if e != nil {
		log.Printf("%v", e)
		return
	}
	body := "This is Http Server developed by Zhang Qichuan:\nThe headers sent by you are:\n"
	for k, v := range data {
		body += k + ": " + v + "\n"
	}
	body = httpServer.SetResponseContent(body)
	(*conn).Write([]byte(body))
	log.Printf("Sent response to client.\n")

}
func (httpServer *HttpServer) StartHttpServer(ctx context.Context) {
	defer wg.Done() //用来记录StartHttpServer函数完成的
	l, e := net.Listen("tcp", httpServer.listenAddress+":"+httpServer.listenPort)
	if e != nil {
		log.Printf("Starting Http Server failed.\n")
		return
	}
	defer func() {
		log.Printf("The Server closed.\n")
	}()

	log.Printf("Listening a Http Server...\n")
	connChannel := make(chan net.Conn)
	errChannel := make(chan error)
	for {

		//在本循环内，始终等待新的客户端发起连接请求
		wg.Add(1)
		go func() {
			defer wg.Done()
			conn, e := l.Accept()
			if e == nil {
				connChannel <- conn
			} else {
				errChannel <- e
			}
		}()
		select {
		case <-ctx.Done():
			log.Printf("Received a termination singal from the console,Closing \n")
			l.Close()
			return

		case conn := <-connChannel:
			wg.Add(1)
			go httpServer.ResponseHttp(&conn)
		case e := <-errChannel:
			log.Printf("%v\n", e)
		}
	}
}
func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()
	wg.Add(1)
	server := HttpServer{
		timeout:       3,
		maxSize:       8 * 1024,
		listenPort:    "80",
		listenAddress: "0.0.0.0",
	}
	go server.StartHttpServer(ctx)
	wg.Wait()
}
